/**
 * 
 * The ConnectionManager is the connection-layer on top of the game.
 * 
 * Author: Matthias Van Eeghem <matthias@van-eeghem.com>
 * All rights reserved.
 * 
 */

package com.bomberman.connection;

import java.awt.event.KeyEvent;
import java.io.IOException;

import com.bomberman.Main;
import com.bomberman.core.Field;
import com.bomberman.core.Game;
import com.bomberman.core.GameState;
import com.bomberman.core.GameState.eState;
import com.bomberman.player.PlayerManager;

public class ConnectionManager 
{
	// Holds the game object for the application
	private Game game;
	// Holds whether or not the player is hosting the game
	private boolean isHost;
	// Holds the server object, null when the player isn't hosting
	volatile ServerConnectionManager server = null;
	// Holds the client object, null when the player is the host
	volatile ClientConnectionManager client = null;

	/**
	 * Constructor for the ConnectionManager. This makes the player host a game
	 * 
	 * @param main
	 * @throws IOException
	 */
	public ConnectionManager(Main main) throws IOException
	{
		// Set the gamestate
		GameState.setGameState(eState.GameStateConnecting);
		
		// Initialise a new game object
		game = new Game(main, true);
		
		// The player is hosting
		isHost = true;
		
		// Initalise the server object
		server = new ServerConnectionManager(this);
		
		// Run the server in a seperate thread
		new Thread(new Runnable() 
		{
			public void run() 
			{
				try {
					server.run();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}).start();
		
		// Generate a random field
		Field.generate();
		
		// Create the local player 
		PlayerManager.addPlayer(Main.playerName, PlayerManager.getEmptySlot(), PlayerManager.getSpawnPositionForID(0).getRow(), PlayerManager.getSpawnPositionForID(0).getColumn());
	}
	
	/**
	 * Constructor for the ConnectionManager, makes the player join a game.
	 * 
	 * @param main 
	 * @param IP The ip to connect to
	 * @param Port The port to connect to
	 * @throws IOException
	 * @throws ClassNotFoundException
	 */
	public ConnectionManager(Main main, final String IP, final int Port) throws IOException, ClassNotFoundException
	{
		// Set the game state
		GameState.setGameState(eState.GameStateConnecting);
		
		// Initialise the game object
		game = new Game(main, false);
		
		// The player isn't hosting
		isHost = false;
		
		// Initialise the client object
		client = new ClientConnectionManager(this, IP, Port);
	
		// Make the client listen for data from the server in a different thread
		new Thread(new Runnable() 
		{
			public void run() 
			{
				try {
					client.run();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}).start();
	}
	
	/**
	 * Is the player hosting or not?
	 * 
	 * @return
	 */
	public boolean isHost()
	{
		return isHost;
	}
	
	/**
	 * Sends data from the server to the client or the other way around, depending whether or not the client is hosting.
	 * 
	 * @param data
	 */
	public void sendData(String data)
	{
		// Is the client hosting?
		if(isHost)
		{
			// Loop through all connections from the server to the clients
			for(ServerConnectionThread thread : server.getClientList())
			{
				// Send the data
				thread.sendData(data);
			}
		}
		else
		{
			// Otherwise, just send the data from the client to the server
			client.sendData(data);
		}
	}
	
	/**
	 * Send data from the server to all players except a certain ID
	 * 
	 * @param playerID The player id to not send the data to
	 * @param data
	 */
	public void sendDataToAllPlayersExcept(int playerID, String data)
	{
		// Loop through all server threads
		for(ServerConnectionThread thread : server.getClientList())
		{
			// Get the player ID that the thread is supposed to send data to
			// And match it against the player id we're supposed to ignore
			if(thread.getPlayerID() != playerID)
				// Send the data
				thread.sendData(data);
		}
	}
	
	/**
	 * Get the game object
	 * 
	 * @return
	 */
	public Game getGameObject()
	{
		return game;
	}
	
	/**
	 * Pass the key event onto the game
	 * 
	 * @param keyEvent
	 */
	public void keyEvent(KeyEvent keyEvent)
	{
		int playerID = game.getLocalPlayer().getID();
		
		// The up button
		if(keyEvent.getKeyCode() == KeyEvent.VK_UP)
		{
			sendData("MOVE UP " + playerID);
		}
		
		// The down button
		if(keyEvent.getKeyCode() == KeyEvent.VK_DOWN)
		{
			sendData("MOVE DOWN " + playerID);
		}
		
		//  The left button
		if(keyEvent.getKeyCode() == KeyEvent.VK_LEFT)
		{
			sendData("MOVE LEFT " + playerID);
		}
		
		// The right button
		if(keyEvent.getKeyCode() == KeyEvent.VK_RIGHT)
		{
			sendData("MOVE RIGHT " + playerID);
		}
		
		if(keyEvent.getKeyCode() == KeyEvent.VK_SPACE)
		{
			sendData("ADD_BOMB " + playerID);
		}
		
		game.keyEvent(keyEvent);
	}
}
